home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
kernel
/
memory.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
6KB
|
171 lines
/* This file contains the drivers for the following special files:
* /dev/null - null device (data sink)
* /dev/mem - absolute memory
* /dev/kmem - kernel virtual memory
* /dev/ram - RAM disk
* /dev/port - i/o ports ((CHIP == INTEL) only)
*
* The driver supports the following operations (using message format m2):
*
* m_type DEVICE PROC_NR COUNT POSITION ADRRESS
* ----------------------------------------------------------------
* | DISK_READ | device | proc nr | bytes | offset | buf ptr |
* |------------+---------+---------+---------+---------+---------|
* | DISK_WRITE | device | proc nr | bytes | offset | buf ptr |
* |------------+---------+---------+---------+---------+---------|
* | DISK_IOCTL | device | | blocks | ram org | |
* ----------------------------------------------------------------
* |SCATTERED_IO| device | proc nr | requests| | iov ptr |
* ----------------------------------------------------------------
*
*
* The file contains one entry point:
*
* mem_task: main entry when system is brought up
*
*/
#include "kernel.h"
#include <minix/callnr.h>
#include <minix/com.h>
#ifdef PORT_DEV
#define NR_RAMS 5 /* number of RAM-type devices */
#else
#define NR_RAMS 4
#endif
PRIVATE message mess; /* message buffer */
PRIVATE phys_bytes ram_origin[NR_RAMS]; /* origin of each RAM disk */
PRIVATE phys_bytes ram_limit[NR_RAMS]; /* limit of RAM disk per minor dev. */
FORWARD int do_mem();
FORWARD int do_setup();
/*===========================================================================*
* mem_task *
*===========================================================================*/
PUBLIC void mem_task()
{
/* Main program of the memory task. */
int r, caller, proc_nr;
/* Initialize this task. */
ram_origin[KMEM_DEV] = numap(SYSTASK, (vir_bytes) 0, (vir_bytes) 1);
ram_limit[KMEM_DEV] = ((phys_bytes) sizes[1] << CLICK_SHIFT) +
ram_origin[KMEM_DEV];
#if (CHIP == INTEL)
if (!protected_mode)
ram_limit[MEM_DEV] = 0x100000; /* above 1M em_xfer word count fails */
else
ram_limit[MEM_DEV] = 0x1000000; /* above 16M not mapped on 386 */
ram_limit[PORT_DEV] = 0x10000;
#else
#if (CHIP == M68000)
ram_limit[MEM_DEV] = MEM_BYTES;
#else
#error /* memory limit not set up */
#endif
#endif
/* Here is the main loop of the memory task. It waits for a message, carries
* it out, and sends a reply.
*/
while (TRUE) {
/* First wait for a request to read or write. */
receive(ANY, &mess);
if (mess.m_source < 0)
panic("mem task got message from ", mess.m_source);
caller = mess.m_source;
proc_nr = mess.PROC_NR;
/* Now carry out the work. It depends on the opcode. */
switch(mess.m_type) {
case DISK_READ: r = do_mem(&mess); break;
case DISK_WRITE: r = do_mem(&mess); break;
case SCATTERED_IO: r = do_vrdwt(&mess, do_mem); break;
case DISK_IOCTL: r = do_setup(&mess); break;
default: r = EINVAL; break;
}
/* Finally, prepare and send the reply message. */
mess.m_type = TASK_REPLY;
mess.REP_PROC_NR = proc_nr;
mess.REP_STATUS = r;
send(caller, &mess);
}
}
/*===========================================================================*
* do_mem *
*===========================================================================*/
PRIVATE int do_mem(m_ptr)
register message *m_ptr; /* pointer to read or write message */
{
/* Read or write /dev/null, /dev/mem, /dev/kmem, /dev/ram or /dev/port. */
int device, count, endport, port, portval;
phys_bytes mem_phys, user_phys;
/* Get minor device number and check for /dev/null. */
device = m_ptr->DEVICE;
if (device < 0 || device >= NR_RAMS) return(ENXIO); /* bad minor device */
if (device==NULL_DEV) return(m_ptr->m_type == DISK_READ ? 0 : m_ptr->COUNT);
/* Set up 'mem_phys' for /dev/mem, /dev/kmem, or /dev/ram. */
if (m_ptr->POSITION < 0) return(ENXIO);
mem_phys = ram_origin[device] + m_ptr->POSITION;
if (mem_phys >= ram_limit[device]) return(0);
count = m_ptr->COUNT;
if(mem_phys + count > ram_limit[device]) count = ram_limit[device] - mem_phys;
/* Determine address where data is to go or to come from. */
user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
(vir_bytes) count);
if (user_phys == 0) return(E_BAD_ADDR);
#ifdef PORT_DEV
/* Do special case of /dev/port. */
if (device == PORT_DEV) {
port = mem_phys;
mem_phys = umap(proc_ptr, D, (vir_bytes) &portval, (vir_bytes) 1);
for (endport = port + count; port != endport; ++port) {
if (m_ptr->m_type == DISK_READ) {
portval = in_byte(port);
phys_copy(mem_phys, user_phys++, (phys_bytes) 1);
} else {
phys_copy(user_phys++, mem_phys, (phys_bytes) 1);
out_byte(port, portval);
}
}
return(count);
}
#endif
/* Copy the data. */
if (m_ptr->m_type == DISK_READ)
phys_copy(mem_phys, user_phys, (long) count);
else
phys_copy(user_phys, mem_phys, (long) count);
return(count);
}
/*===========================================================================*
* do_setup *
*===========================================================================*/
PRIVATE int do_setup(m_ptr)
message *m_ptr; /* pointer to read or write message */
{
/* Set parameters for one of the disk RAMs. */
int device;
device = m_ptr->DEVICE;
if (device != RAM_DEV) return(ENXIO); /* bad minor device */
ram_origin[device] = m_ptr->POSITION;
ram_limit[device] = m_ptr->POSITION + (long) m_ptr->COUNT * BLOCK_SIZE;
return(OK);
}